我們在 D6 - Build Cache 時,說到了 Docker 可以在建置 Image 時複用已經存在的 Image 來加速,
如果在同一台 Server 上執行建置,很容易就可以觀察並確認 Build Cache 的情況,尤其是當建置需要較長時間時,Build Cache 就起到很大的加速作用,
但如果我們是利用 CICD 工具來執行佈署呢?
CICD 工具每一次都會啟動一個新環境在裡面執行,因此如果用同樣的建置方式放到 CICD 工具上,就會每次都是花費最長的時間,沒有得益於 Build Cache,
於是,我今天的內容就是研究如何在 Gitlab CI 中,依然能透過 Build Cache 得到加速,
而為什麼選擇 Gitlab CI,因為目前公司的專案是用 Gitlab CI,我正好能把研究成果用在工作上。
Gitlab CI/CD 這套 CICD 工具,可以在 Repo 中透過 YAML 來定義要自動執行的步驟,當我們把程式碼用 git push 推上去到 Gitlab Repo 時,就會自動讀取設定檔開始執行,
對非公開的專案,Gitlab 也有提供免費額度,每個月有固定的分鐘數可以用,因此即使是私人的專案,讀者也可以自己玩玩看。
除了 Git Server 以外,Gitlab 也可以用來存放 Docker Image,被稱為 Container Registry
,跟 Dockerhub 不一樣的是,Gitlab Container Registry 是以 Gitlab Repo 為單位所提供的服務,
要使用前,需要用 Gitlab 產生的 token 登入,Token 可以是單一 Repo 的 Deploy Token、或是個人的 Personal Access Token,
取得 Token 後,使用指令 docker login
來登入,就可以存取 Container Registry。
接下來說明今天要執行的 CICD 流程,
其中粗體的部分是為了借助 Build Cache 加速而加入的步驟:
docker build
,並加入 --cache-from 參數
在 D6 中提到,我們可以加入 --cache-from
來明確指定要拿來複用 Cache 的 image,
因此為了加速 CICD 建置 image 的步驟,我們會在 Gitlab CICD 環境中拉取 Container Registry 中的 image,也就是前一次 CICD 推上去的 image,
同樣地,因為這是很小的玩具專案,因此有無 Build Cache 的加速,並不會帶來很大的差異,但是能藉這個玩具來確定自己學會使用它。
我們就拿 D5 - Hello World ft. Express 的程式碼來做實驗,第一次的 CICD 執行時會花費完整的時間,
接著我們修改一點點程式碼,加入一支新的 API,確認真的有使用 Build Cache、並成功完成佈署。
接下來就來展示今天的 Gitlab CICD 定義檔,
部分細節可以參考註解上的說明:
## .gitlab-ci.yml
stages:
- deploy
deploy-dev:
stage: deploy
# 只有分支 D09/gitlab-ci-build-cache 才會觸發 CICD
rules:
- if: '$CI_COMMIT_BRANCH == "D09/gitlab-ci-build-cache"'
# 指定 Gitlab CICD 要啟動什麼 Image: 使用 Docker Client
image: docker
# 同時啟動 Docker Daemon 給 Docker Client 使用
# 可以回想一下 D7 的 Docker 架構圖
services:
- docker:dind
# 在開始前,登入 Gitlab Container Registry
# 並且放置要 SSH 進入 Server 使用的 Private Key
before_script:
# 這幾個環境變數是 Gitlab CICD 預設提供的
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
# 拿取存放在 CICD Variables 的 Private Key 並設置
- mkdir -p ~/.ssh/
- echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
script:
# Build docker image
- cd D05-hello-world-server
# 一定要先把 image 拉下來,才能作為 Build Cache 使用
# 同時,最後面加入 `|| true`,確保即使是第一次執行還沒有 image 時,也不會導致 CICD 執行失敗
- docker pull ${CI_REGISTRY_IMAGE}/hello-world-server || true
# 以 --cache-from 參數來指定 Build Cache
- docker build -t ${CI_REGISTRY_IMAGE}/hello-world-server .
--cache-from ${CI_REGISTRY_IMAGE}/hello-world-server
- docker images
# 把新的 image 推上去
- docker push ${CI_REGISTRY_IMAGE}/hello-world-server
# Deploy
# SSH 進入 Server
- ssh -tt -o StrictHostKeyChecking=no ${SERVER_USER}@${SERVER_HOSTNAME} "
# sudo su 是為了以 root 身分執行指令
sudo su - -c '
# 先拉取 image 再關閉原本的 container,可以減少服務的 down time
docker pull ${CI_REGISTRY_IMAGE}/hello-world-server &&
docker stop my-hello-world-server &&
docker rm my-hello-world-server &&
docker run --detach --publish=3000:3000 --name=my-hello-world-server ${CI_REGISTRY_IMAGE}/hello-world-server
'
"
$ docker build -t ${CI_REGISTRY_IMAGE}/hello-world-server . --cache-from ${CI_REGISTRY_IMAGE}/hello-world-server
Step 1/6 : FROM node:16-slim
16-slim: Pulling from library/node
...
Status: Downloaded newer image for node:16-slim
---> 572389d8c38d
Step 2/6 : WORKDIR /app
---> Running in b9884f4154fb
Removing intermediate container b9884f4154fb
---> 7613e3b5b860
Step 3/6 : COPY ./package*.json ./
---> 3bd5adab41ba
Step 4/6 : RUN npm ci
---> Running in 19b73e3e7d67
added 57 packages, and audited 58 packages in 1s
7 packages are looking for funding
---> ca0edb22da42
Step 5/6 : COPY . .
---> 00d80b3a08fa
Step 6/6 : CMD ["npm", "start"]
---> Running in 7a9ef41cdbc2
Removing intermediate container 7a9ef41cdbc2
---> 0e760d3c7294
Successfully built 0e760d3c7294
Successfully tagged registry.gitlab.com/louis222220/2022-ithelp-docker-is-not-so-hard/hello-world-server:latest
Using cache
的字樣,顯示有使用 Build Cache$ docker build -t ${CI_REGISTRY_IMAGE}/hello-world-server . --cache-from ${CI_REGISTRY_IMAGE}/hello-world-server
Step 1/6 : FROM node:16-slim
16-slim: Pulling from library/node
...
Status: Downloaded newer image for node:16-slim
---> 572389d8c38d
Step 2/6 : WORKDIR /app
---> Using cache
---> 7152da344010
Step 3/6 : COPY ./package*.json ./
---> Using cache
---> 57221dd03638
Step 4/6 : RUN npm ci
---> Using cache
---> 786b3ba3622e
Step 5/6 : COPY . .
---> 07d4ffad255d
Step 6/6 : CMD ["npm", "start"]
---> Running in 430c13426a44
Removing intermediate container 430c13426a44
---> 65635b7b8505
Successfully built 65635b7b8505
Successfully tagged registry.gitlab.com/louis222220/2022-ithelp-docker-is-not-so-hard/hello-world-server:latest
# On server
$ curl localhost:3000/hola
{"hola":"world"}
以上,就是我今天的研究內容,
本次的程式碼可以在 Gitlab 找到,
Gitlab CICD 執行過程的細節也可以看連結 #3078496874、#3078520292,
那我們明天再會。